#include "app_main.h"
#include "drv_misc.h"
#include "elog.h"
#include "elog_port.h"
#include "param.h"
#include "park.h"
#include "radar_detect.h"
#include "vz_log.h"
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

typedef struct TestCtx {
  SOCTrigCb SocTrigCbFunc;
  void *SocTrigCbParam;
  RadarTrigCb RadarTrigCbFunc;
  void *RadarTrigCbParam;
  ParkCtx_t *BusCtx;
  uint64_t exec_interval;
  bool timing_retart;
  uint64_t time_stamp;
} TestCtx_t;

TestCtx_t *g_TestCtx = NULL;

bool App_IsTimeInPeriod(uint8_t time_begin[4], uint8_t time_end[4],
                        DevTime_t *time) {
  bool is_after_begin = false;
  bool is_before_end = false;
  log_v("begin:%d-%d-%d, end:%d-%d-%d, time:%d-%d-%d", time_begin[2],
        time_begin[1], time_begin[0], time_end[2], time_end[1], time_end[0],
        time->hour, time->minute, time->second);
  if (time->hour > time_begin[2]) {
    is_after_begin = true;
  } else if ((time->hour == time_begin[2]) && (time->minute > time_begin[1])) {
    is_after_begin = true;
  } else if ((time->hour == time_begin[2]) && (time->minute == time_begin[1]) &&
             (time->second > time_begin[0])) {
    is_after_begin = true;
  }
  if (!is_after_begin) {
    return false;
  }
  if (time->hour < time_end[2]) {
    is_before_end = true;
  } else if ((time->hour == time_end[2]) && (time->minute <= time_end[1])) {
    is_before_end = true;
  } else if ((time->hour == time_end[2]) && (time->minute == time_end[1]) &&
             (time->second <= time_end[0])) {
    is_before_end = true;
  }
  return is_before_end && is_after_begin;
}

static int soc_pwr_fuc(ParkCtx_t *ctx, ParamInfo_t *p,
                       SocWorkStatus_e soc_sta) {
  if (!g_TestCtx->SocTrigCbFunc) {
    return 0;
  }
  g_TestCtx->SocTrigCbFunc((int)soc_sta, g_TestCtx->SocTrigCbParam);
  return 0;
}

int RadarDet_Init(const char *log_file, LOG_OUTPOS_e log_pos) {
  if (g_TestCtx) {
    return -1;
  }
  g_TestCtx = malloc(sizeof(TestCtx_t));
  if (!g_TestCtx) {
    return -1;
  }
  memset(g_TestCtx, 0, sizeof(TestCtx_t));
  ParamInfo_t param = {0};

  elog_set_log_output_pos(log_file, log_pos);

  elog_init();
  elog_set_fmt(ELOG_LVL_ASSERT, ELOG_FMT_ALL & ~ELOG_FMT_DIR);
  elog_set_fmt(ELOG_LVL_ERROR, ELOG_FMT_LVL | ELOG_FMT_TIME);
  elog_set_fmt(ELOG_LVL_WARN, ELOG_FMT_LVL | ELOG_FMT_TIME);
  elog_set_fmt(ELOG_LVL_INFO,
               ELOG_FMT_LVL | ELOG_FMT_TIME | ELOG_FMT_FUNC | ELOG_FMT_LINE);
  elog_set_fmt(ELOG_LVL_DEBUG,
               ELOG_FMT_LVL | ELOG_FMT_TIME | ELOG_FMT_FUNC | ELOG_FMT_LINE);
  elog_set_fmt(ELOG_LVL_VERBOSE,
               ELOG_FMT_LVL | ELOG_FMT_TIME | ELOG_FMT_FUNC | ELOG_FMT_LINE);
  Param_Init();
  elog_set_filter_lvl(ELOG_LVL_INFO);
  /* start EasyLogger */
  elog_start();
  VzLog_Init();
  log_i("main start");
  LOG_TRACE_SYS(LL_KEY, LOG_ID_SYS_POWER_ON, "SYS POWER ON");
  Param_Init();
  Param_Read(&param);
  g_TestCtx->BusCtx = malloc(sizeof(ParkCtx_t));
  if (!g_TestCtx->BusCtx) {
    return -1;
  }

  Park_Init(g_TestCtx->BusCtx, &param);
  Park_SetMiscCallback(soc_pwr_fuc);
  return 0;
}

int RadarDet_Uninit() {
  if (!g_TestCtx) {
    return 0;
  }
  Park_Unint(g_TestCtx->BusCtx);
  free(g_TestCtx->BusCtx);
  VzLog_Uninit();
  elog_deinit();
  free(g_TestCtx);
  g_TestCtx = NULL;
  return 0;
}

static int GetTimeStamp(BusWorkInfo_t *info) {
  if (g_TestCtx->timing_retart) {
    g_TestCtx->timing_retart = false;
    DrvMisc_GetSec(&g_TestCtx->time_stamp);
    g_TestCtx->time_stamp = 1000 * g_TestCtx->time_stamp;
  } else {
    g_TestCtx->time_stamp += g_TestCtx->exec_interval;
  }
  struct tm *tm_info;
  time_t ts = g_TestCtx->time_stamp / 1000;
  tm_info = gmtime(&ts);
  info->cur_time.year = tm_info->tm_year + 1900;
  info->cur_time.month = tm_info->tm_mon + 1;
  info->cur_time.day = tm_info->tm_mday;
  info->cur_time.hour = tm_info->tm_hour;
  info->cur_time.minute = tm_info->tm_min;
  info->cur_time.second = tm_info->tm_sec;
  info->cur_time.time_zone = 8;
  info->cur_time.millisecond = 0;
  info->time_stamp = g_TestCtx->time_stamp / 1000;
  return 0;
}

int GetParam(BusWorkInfo_t *work_info) {
  ParamInfo_t p = {0};
  p.version = 4;
  p.info.radar_sensitivity = 50;        /*雷达触发灵敏度, 0~100*/
  p.info.radar_fault_thresh = 50;       /*雷达错误门限，0~100*/
  p.info.radar_trig_interval = 1;       /*雷达触发间隔，单位s*/
  p.info.pro_type = 0;                  /*产品类型，参考ProductType_e*/
  p.info.solar_batt_valid = true;       /*是否具有太阳能电池板*/
  p.info.timing_pic_interval = 30 * 60; /*秒图间隔，单位s*/
  p.info.timing_pic_empty_en = false; /*无车秒图开关，0关闭，1打开*/
  p.info.heart_interval = 0;          /*心跳超时间隔，单位s*/
  p.info.batt_door_alarm_en = false;  /*电池门报警使能*/
  p.info.batt_door_alarm_interval = 24 * 60 * 60; /*电池报警间隔，单位s*/
  p.info.batt_low_thresh = 5; /*低电量报警门限，单位电池容量百分比*/
  p.info.batt_low_alarm_interval = 24 * 60 * 60; /*低电量报警间隔，单位s*/
  p.info.parking_stable_interval = 30; /*停稳和空场超时间隔，单位s*/
  p.info.power_soc_disable = false;    /*调试模式，1使能，0关闭*/
  p.info.watchdog_enable = false;      /*看门狗是否使能*/
  p.info.watchdog_timeout = 5 * 60;    /*看门狗超时时间，单位s*/
  p.info.radar_cover_dist = 20;        /*雷达遮挡距离阈值，单位cm*/
  p.info.radar_enter_dist = 580;       /*雷达驶入阈值，单位cm*/
  p.info.radar_exit_dist = 300;        /*车辆空场距离阈值，单位cm*/
  p.info.radar_change_dist = 30;       /*雷达阈值变化阈值，单位cm*/
  p.info.radar_stable_dist_thresh = 15; /*雷达停稳阈值，单位cm*/
  p.info.wakeup_interval = 1;           /*MCU唤醒间隔，单位s*/
  p.info.factory_mode = 0;              /*工厂模式，0关闭，1打开*/
  p.info.batt_protect_thresh = 0; /*电量保护阈值，单位电池容量百分比*/
  p.info.batt_low_alarm_en = false;                 /*电量低报警使能*/
  p.info.radar_fault_alarm_en = false;              /*雷达错误使能*/
  p.info.radar_fault_alarm_interval = 24 * 60 * 60; /*雷达错误报警间隔, */
  memcpy(&work_info->param, &p, sizeof(ParamInfo_t));
  Param_AdvRead(&work_info->param_adv);
  work_info->param_adv.info.parking_out_interval = 30;
  return 0;
}

int RadarDet_Exec() {
  if (!g_TestCtx) {
    return -1;
  }
  BusWorkInfo_t work_info = {0};
  GetParam(&work_info);
  DrvMisc_GetSec(&work_info.time_stamp);
  work_info.radar_shut = false;
  GetTimeStamp(&work_info);
  Park_Exec(g_TestCtx->BusCtx, &work_info);
  return 0;
}

int RadarDet_SetSOCTrigCallBack(SOCTrigCb cb, void *param) {
  if ((!cb) || (!g_TestCtx)) {
    return -1;
  }
  g_TestCtx->SocTrigCbFunc = cb;
  g_TestCtx->SocTrigCbParam = param;
  return 0;
}

int RadarDet_SetRadarTrigCallBack(RadarTrigCb cb, void *param) {
  if ((!cb) || (!g_TestCtx)) {
    return -1;
  }
  g_TestCtx->RadarTrigCbFunc = cb;
  g_TestCtx->RadarTrigCbParam = param;
  return 0;
}

int RadarDet_SetAlgResult(uint8_t park_state, uint8_t has_plate) {
  AlgResult_t alg_resl = {0};
  alg_resl.reco = park_state;
  alg_resl.has_plate = has_plate;
  return Park_SetAlgResult(&alg_resl);
}

int RadarDet_ShutSocPower() { return Park_SetSocPowerDown(); }

int RadarDet_GetTrigInfo(SocTrigInfo_t *info) {
  int ret = 0;
  TriggerInfo_t t_info = {0};
  ret = Park_GetTriggerType(&t_info);
  if (ret != 0) {
    return ret;
  }
  memcpy(info, &t_info, sizeof(TriggerInfo_t));
  return 0;
}

int Radar_Trigger(RadarData_t *data) {
  int ret = 0;
  if (!g_TestCtx) {
    return -1;
  }
  ret = g_TestCtx->RadarTrigCbFunc(&data->dist, &data->amp,
                                   g_TestCtx->RadarTrigCbParam);
  if (ret == 0) {
    log_i("radar: dist: %d, amp: %d", data->dist, data->amp);
  } else {
    log_i("radar trigger failed");
  }
  return ret;
}

int RadarDet_SetExecInterval(uint64_t interval_in_ms) {
  g_TestCtx->timing_retart = true;
  g_TestCtx->exec_interval = interval_in_ms;
  return 0;
}

int Radar_InitSetttings() { return 0; }
void Radar_PowerReset() {}
int Radar_AdjustUpgrade() { return 0; }